{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _nb_results:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After an algorithm has been executed a result object is returned. In the following, single- and multi-objective runs with and without constraints are shown and the corresponding `Result` object is explained:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymoo.algorithms.so_genetic_algorithm import GA\n",
    "from pymoo.factory import get_problem\n",
    "from pymoo.optimize import minimize\n",
    "\n",
    "\n",
    "problem = get_problem(\"sphere\")\n",
    "algorithm = GA(pop_size=5)\n",
    "res = minimize(problem,\n",
    "               algorithm,\n",
    "               ('n_gen', 30),\n",
    "               seed=1)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After an algorithm has been executed, a result object is returned. In the following, single- and multi-objective runs with and without constraints are shown, and the corresponding `Result` object is explained:\n",
    "\n",
    "In this single-objective optimization problem, there exists a single best solution that was found. \n",
    "The result directly contains the best-found values in the corresponding spaces. \n",
    "\n",
    "- `res.X` design space values are \n",
    "- `res.F` objective spaces values\n",
    "- `res.G` constraint values\n",
    "- `res.CV` aggregated constraint violation\n",
    "- `res.algorithm` algorithm object\n",
    "- `res.pop` final population object\n",
    "- `res.history` history of algorithm object. (only if `save_history` has been enabled during the algorithm initialization)\n",
    "- `res.time` the time required to run the algorithm\n",
    "\n",
    "Note that when the `minimize` function is called, a deep copy of the algorithm object is created.\n",
    "This ensures that two independent runs with the same algorithm and same random seed have the same results without any side effects."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0.38401994, 0.51096839, 0.51958345, 0.50705362, 0.64625327,\n",
       "        0.52972181, 0.51346167, 0.57393803, 0.48975355, 0.49213286]),\n",
       " array([0.04209328]),\n",
       " None,\n",
       " array([0.]))"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.X, res.F, res.G, res.CV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<pymoo.algorithms.so_genetic_algorithm.GA at 0x7ff5e9af89e8>,\n",
       " Population([<pymoo.model.individual.Individual object at 0x7ff5e9b1c198>,\n",
       "             <pymoo.model.individual.Individual object at 0x7ff5e9b35438>,\n",
       "             <pymoo.model.individual.Individual object at 0x7ff5e9b1cfd0>,\n",
       "             <pymoo.model.individual.Individual object at 0x7ff5e9b1c128>,\n",
       "             <pymoo.model.individual.Individual object at 0x7ff5e9b1c6d8>],\n",
       "            dtype=object))"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.algorithm, res.pop"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The values from the final population can be extracted by using the `get` method. The population object is used internally and store information for each individual. The `get` method allows returning vectors or matrices based on the provided properties."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[0.38401994, 0.51096839, 0.51958345, 0.50705362, 0.64625327,\n",
       "         0.52972181, 0.51346167, 0.57393803, 0.48975355, 0.49213286],\n",
       "        [0.38401994, 0.51096839, 0.51958345, 0.50705362, 0.64625327,\n",
       "         0.52972181, 0.51346167, 0.57393803, 0.51785226, 0.49213286],\n",
       "        [0.38401994, 0.51099826, 0.44223106, 0.50705362, 0.64625327,\n",
       "         0.52808581, 0.51346167, 0.57393803, 0.39462856, 0.49213286],\n",
       "        [0.38401994, 0.51099826, 0.44223106, 0.50705362, 0.64625327,\n",
       "         0.52864113, 0.51346167, 0.57393803, 0.39462856, 0.49213286],\n",
       "        [0.38401994, 0.47389685, 0.44223106, 0.50705362, 0.64625327,\n",
       "         0.52808581, 0.51346167, 0.57393803, 0.39462856, 0.49213286]]),\n",
       " array([[0.04209328],\n",
       "        [0.04230699],\n",
       "        [0.05595125],\n",
       "        [0.05598275],\n",
       "        [0.05651167]]))"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.pop.get(\"X\"), res.pop.get(\"F\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this run, the problem did not have any constraints, and `res.G` evaluated to `None`.\n",
    "Also, note that `res.CV` will always be set to `0`, no matter if the problem has constraints or not."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let us consider a problem that has, in fact, constraints:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===========================================================================\n",
      "n_gen |  n_eval |   cv (min)   |   cv (avg)   |     fopt     |     favg    \n",
      "===========================================================================\n",
      "    1 |       5 |  1.35027E+02 |  5.47570E+02 |            - |            -\n",
      "    2 |      10 |  1.35027E+02 |  3.16525E+02 |            - |            -\n",
      "    3 |      15 |  1.35027E+02 |  2.16131E+02 |            - |            -\n",
      "    4 |      20 |  1.35027E+02 |  1.60240E+02 |            - |            -\n",
      "    5 |      25 |  1.33435E+02 |  1.38575E+02 |            - |            -\n"
     ]
    }
   ],
   "source": [
    "problem = get_problem(\"g01\")\n",
    "algorithm = GA(pop_size=5)\n",
    "res = minimize(problem,\n",
    "               algorithm,\n",
    "               ('n_gen', 5),\n",
    "               verbose=True,\n",
    "               seed=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(None, None, None, None)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.X, res.F, res.G, res.CV"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, the algorithm was not able to find any feasible solution in 5 generations. Therefore, all values contained in the results are equals to `None`. If the least feasible solution should be returned when no feasible solution was found, the flag `return_least_infeasible` can be enabled:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===========================================================================\n",
      "n_gen |  n_eval |   cv (min)   |   cv (avg)   |     fopt     |     favg    \n",
      "===========================================================================\n",
      "    1 |       5 |  1.35027E+02 |  5.47570E+02 |            - |            -\n",
      "    2 |      10 |  1.35027E+02 |  3.16525E+02 |            - |            -\n",
      "    3 |      15 |  1.35027E+02 |  2.16131E+02 |            - |            -\n",
      "    4 |      20 |  1.35027E+02 |  1.60240E+02 |            - |            -\n",
      "    5 |      25 |  1.33435E+02 |  1.38575E+02 |            - |            -\n"
     ]
    }
   ],
   "source": [
    "problem = get_problem(\"g01\")\n",
    "algorithm = GA(pop_size=5)\n",
    "res = minimize(problem,\n",
    "               algorithm,\n",
    "               ('n_gen', 5),\n",
    "               verbose=True,\n",
    "               return_least_infeasible=True,\n",
    "               seed=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([ 0.75014431,  0.93402157,  0.45981887,  0.45896477,  0.78927933,\n",
       "         0.10322601,  0.74930314,  0.9085955 ,  0.29361415, 28.77753386,\n",
       "        13.00285721,  1.93669579,  0.78207866]),\n",
       " array([-43.6144102]),\n",
       " array([35.14872283, 23.13415601,  7.72723386, 22.77637934,  5.53068468,\n",
       "        -1.74185514, 27.070325  , 12.04710206, -0.17410937]),\n",
       " array([133.43460378]))"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.X, res.F, res.G, res.CV"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have made this design decision, because an infeasible solution can often not be considered as a solution\n",
    "of the optimization problem. Therefore, having a solution equals to `None` indicates the fact no feasible solution has been found."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the problem has multiple objectives, the result object has the same structure but `res.X`, `res.F`, `res .G`, `res.CV` is a set \n",
    "of non-dominated solutions instead of a single one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymoo.algorithms.nsga2 import NSGA2\n",
    "\n",
    "problem = get_problem(\"zdt2\")\n",
    "algorithm = NSGA2()\n",
    "res = minimize(problem,\n",
    "               algorithm,\n",
    "               ('n_gen', 10),\n",
    "               seed=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[4.02723032e-01, 2.92285190e+00],\n",
       "       [2.42936792e-03, 3.09049957e+00],\n",
       "       [6.42640810e-05, 3.80452248e+00],\n",
       "       [9.03843390e-02, 2.97779402e+00],\n",
       "       [7.51601609e-04, 3.12489259e+00],\n",
       "       [2.66638116e-05, 4.15122904e+00],\n",
       "       [5.32367109e-01, 2.91333135e+00],\n",
       "       [7.51074119e-05, 3.17766175e+00],\n",
       "       [9.96726161e-01, 2.73633323e+00],\n",
       "       [9.37668137e-01, 2.76323527e+00],\n",
       "       [2.78148785e-05, 3.90537318e+00]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "res.F"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
